/**
 * Copyright &copy; 2015-2020 <a href="http://www..org/"></a> All rights reserved.
 */
package cn.gzjp.common.web;

import java.beans.PropertyEditorSupport;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import javax.validation.Validator;

import cn.gzjp.common.config.Global;
import cn.gzjp.common.constant.Constants;
import cn.gzjp.modules.woms.entity.Event;
import cn.gzjp.modules.wx.service.QyWxService;
import cn.hutool.core.util.StrUtil;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.cp.bean.WxCpMessage;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.ui.Model;
import org.springframework.validation.BindException;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import cn.gzjp.common.beanvalidator.BeanValidators;
import cn.gzjp.common.mapper.JsonMapper;
import cn.gzjp.common.utils.DateUtils;

/**
 * 控制器支持类
 * @author 
 * @version 2013-3-23
 */
public abstract class BaseController {
	

	
	protected static JsonMapper mapper = JsonMapper.getInstance();

	public final static AjaxResult successResult = new AjaxResult(true, "操作成功！");

	public final static AjaxResult errorResult = new AjaxResult(false, "操作失败！");

	public final static String RETURN_OK;
	public final static String RETURN_BAD;
	static {
		RETURN_OK = mapper.toJson(successResult);
		RETURN_BAD = mapper.toJson(errorResult);

	}

	/**
	 * 日志对象
	 */
	protected Logger logger = LoggerFactory.getLogger(getClass());

	/**
	 * 管理基础路径
	 */
	@Value("${adminPath}")
	protected String adminPath;
	
	/**
	 * 前端基础路径
	 */
	@Value("${frontPath}")
	protected String frontPath;
	
	/**
	 * 前端URL后缀
	 */
	@Value("${urlSuffix}")
	protected String urlSuffix;
	
	/**
	 * 验证Bean实例对象
	 */
	@Autowired
	protected Validator validator;

	/**
	 * 服务端参数有效性验证
	 * @param object 验证的实体对象
	 * @param groups 验证组
	 * @return 验证成功：返回true；严重失败：将错误信息添加到 message 中
	 */
	protected boolean beanValidator(Model model, Object object, Class<?>... groups) {
		try{
			BeanValidators.validateWithException(validator, object, groups);
		}catch(ConstraintViolationException ex){
			List<String> list = BeanValidators.extractPropertyAndMessageAsList(ex, ": ");
			list.add(0, "数据验证失败：");
			addMessage(model, list.toArray(new String[]{}));
			return false;
		}
		return true;
	}
	
	/**
	 * 服务端参数有效性验证
	 * @param object 验证的实体对象
	 * @param groups 验证组
	 * @return 验证成功：返回true；严重失败：将错误信息添加到 flash message 中
	 */
	protected boolean beanValidator(RedirectAttributes redirectAttributes, Object object, Class<?>... groups) {
		try{
			BeanValidators.validateWithException(validator, object, groups);
		}catch(ConstraintViolationException ex){
			List<String> list = BeanValidators.extractPropertyAndMessageAsList(ex, ": ");
			list.add(0, "数据验证失败：");
			addMessage(redirectAttributes, list.toArray(new String[]{}));
			return false;
		}
		return true;
	}
	
	/**
	 * 服务端参数有效性验证
	 * @param object 验证的实体对象
	 * @param groups 验证组，不传入此参数时，同@Valid注解验证
	 * @return 验证成功：继续执行；验证失败：抛出异常跳转400页面。
	 */
	protected void beanValidator(Object object, Class<?>... groups) {
		BeanValidators.validateWithException(validator, object, groups);
	}
	
	/**
	 * 添加Model消息
	 */
	protected void addMessage(Model model, String... messages) {
		StringBuilder sb = new StringBuilder();
		for (String message : messages){
			sb.append(message).append(messages.length>1?"<br/>":"");
		}
		model.addAttribute("message", sb.toString());
	}
	
	/**
	 * 添加Flash消息
	 */
	protected void addMessage(RedirectAttributes redirectAttributes, String... messages) {
		StringBuilder sb = new StringBuilder();
		for (String message : messages){
			sb.append(message).append(messages.length>1?"<br/>":"");
		}
		redirectAttributes.addFlashAttribute("message", sb.toString());
	}
	
	/**
	 * 客户端返回JSON字符串
	 * @param response
	 * @param object
	 * @return
	 */
	protected String renderString(HttpServletResponse response, Object object) {
		return renderString(response, JsonMapper.toJsonString(object));
	}
	
	/**
	 * 客户端返回字符串
	 * @param response
	 * @param string
	 * @return
	 */
	protected String renderString(HttpServletResponse response, String string) {
		try {
			response.reset();
	        response.setContentType("application/json");
	        response.setCharacterEncoding("utf-8");
			response.getWriter().print(string);
			return null;
		} catch (IOException e) {
			return null;
		}
	}

	/**
	 * 参数绑定异常
	 */
	@ExceptionHandler({BindException.class, ConstraintViolationException.class, ValidationException.class})
    public String bindException() {  
        return "error/400";
    }
	
	/**
	 * 授权登录异常
	 */
	@ExceptionHandler({AuthenticationException.class})
    public String authenticationException() {  
        return "error/403";
    }
	
	/**
	 * 初始化数据绑定
	 * 1. 将所有传递进来的String进行HTML编码，防止XSS攻击
	 * 2. 将字段中Date类型转换为String类型
	 */
	@InitBinder
	protected void initBinder(WebDataBinder binder) {
		// String类型转换，将所有传递进来的String进行HTML编码，防止XSS攻击
		binder.registerCustomEditor(String.class, new PropertyEditorSupport() {
			@Override
			public void setAsText(String text) {
				setValue(text == null ? null : StringEscapeUtils.escapeHtml4(text.trim()));
			}
			@Override
			public String getAsText() {
				Object value = getValue();
				return value != null ? value.toString() : "";
			}
		});
		// Date 类型转换
		binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
			@Override
			public void setAsText(String text) {
				setValue(DateUtils.parseDate(text));
			}
//			@Override
//			public String getAsText() {
//				Object value = getValue();
//				return value != null ? DateUtils.formatDateTime((Date)value) : "";
//			}
		});
	}
	/**
	 * SpingMVC重定向
	 * @param format
	 * @param arguments
	 * @return
	 */
	public String redirect(String format, Object... arguments) {
		return new StringBuffer("redirect:").append(adminPath).append(MessageFormat.format(format, arguments)).toString();
	}
	
	public String redirectFront(String format, Object... arguments) {
		return new StringBuffer("redirect:").append(frontPath).append(MessageFormat.format(format, arguments)).toString();
	}
	public String getBasePath(HttpServletRequest request){
		 String path = request.getContextPath();
			String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
			+ path;
		return basePath;
	}
	@Autowired
	private QyWxService qyWxService;


	@Value("${corp.id}")
	protected String corpId;

	@Value("${corp.debug}")
	protected boolean corpDebug;

	//下发企业推送
	public void sendQyWxMessage(Event event, String agentId, String title,String content,String toUser){
		WxCpMessage message = new WxCpMessage();
		message.setAgentId(agentId);
		message.setMsgType(WxConsts.CUSTOM_MSG_NEWS);
		WxCpMessage.WxArticle article = new WxCpMessage.WxArticle();
		if(StrUtil.isNotBlank(event.getFaultPic())){
			article.setPicUrl(Global.getConfig("projectUrl")+"/static/front/cms/img/event_default.png");
		}
		article.setDescription(content);
		article.setTitle(title);
		String uri = "";
	    if(Constants.AgentId.assigner.equals(agentId)){
			uri = "assigner";

		}else if(Constants.AgentId.pm.equals(agentId)){
			uri = "pm";

		}else if(Constants.AgentId.enginer.equals(agentId)){
			uri = "engineer";

		}
		else if(Constants.AgentId.achieve.equals(agentId)){
			uri = "achieve";

		}
		article.setUrl(Global.getConfig("projectUrl") + Global.getFrontPath()+"/"+uri+"/event?id=" + event.getId()+"&userId="+toUser+"&agentId="+agentId);
		List<WxCpMessage.WxArticle> articles = new ArrayList<WxCpMessage.WxArticle>();
		articles.add(article);
		message.setArticles(articles);
		message.setToUser(toUser);
		if(!corpDebug){//测试模式, 发不了通知
			try {
				qyWxService.messageSend(corpId, agentId, message);
			} catch (WxErrorException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

	}


}
